package com.example.smartcitydemo.base

import android.util.Log
import com.example.smartcity_jscs.network.ResultStates.Resource
import com.example.smartcitydemo.bean.BaseListResponse
import com.example.smartcitydemo.bean.BaseResponse
import com.example.smartcitydemo.bean.SuccessBean
import com.example.smartcitydemo.exception.AppExcpetion
import com.example.smartcitydemo.exception.ErrorType
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.flow
import kotlinx.coroutines.flow.flowOn

/**
 * @PACKAGE_NAME: com.example.smartcitydemo.base
 * @NAME: Caleb.F
 * @DATE: 2021/11/4 10:59
 * @Email: 1919796283@qq.com
 */
open class BaseRepo {

    protected suspend fun <RequestType, ResponseType> request(
        netRequest: suspend () -> BaseResponse<RequestType>,
        datachange: (RequestType) -> (ResponseType)
    ): Flow<Resource<ResponseType>> {
        //此处抓异常抓不住
        return flow {
            val netRequestResult = netRequest()
            if (netRequestResult.code == 200) {
                if (netRequestResult.data == null) {
                    throw AppExcpetion(
                        ErrorType.NO_CONTENT_ERROR,
                        RuntimeException(ErrorType.NO_CONTENT_ERROR.msg)
                    )
                } else {
                    val newResult = datachange.invoke(netRequestResult.data)
                    emit(Resource.Success(newResult))
                }
            } else {
                handleResponseErrorCode(netRequestResult.code, netRequestResult.msg)
            }
        }.flowOn(Dispatchers.IO)
    }


    protected suspend fun <RequestType, ResponseType> requestListData(
        netRequest: suspend () -> BaseListResponse<RequestType>,
        datachange: (List<RequestType>) -> (List<ResponseType>)
    ): Flow<Resource<List<ResponseType>>> {
        //此处抓异常抓不住
        return flow {
            val netRequestResult = netRequest()
            when (netRequestResult.code) {
                200 -> {
                    if (netRequestResult.total == 0) {
                        throw AppExcpetion(
                            ErrorType.NO_CONTENT_ERROR,
                            RuntimeException(ErrorType.NO_CONTENT_ERROR.msg))

                    } else {
                        val newResult = datachange.invoke(netRequestResult.rows)
                        emit(Resource.Success(newResult))
                    }
                }
                else ->
                    handleResponseErrorCode(netRequestResult.code, netRequestResult.msg)
            }
        }.flowOn(Dispatchers.IO)
    }

    /**
     * 登录、点赞等涉及到交互的请求
     * @param netRequest SuspendFunction0<BaseResponse<RequestType>>
     * @param datachange Function1<RequestType, ResponseType>
     * @return Flow<Resource<ResponseType>>
     */
    protected suspend fun requestCommonData(
        netRequest: suspend () -> SuccessBean
    ): Flow<Resource<String>> {
        //此处抓异常抓不住
        return flow {
            val netRequestResult = netRequest()
            if (netRequestResult.code == 200) {
                emit(Resource.Success(netRequestResult.token!!))
            } else {
                handleResponseErrorCode(netRequestResult.code, netRequestResult.msg)
            }
        }.flowOn(Dispatchers.IO)
    }

    /**
     * kotlin中不需要显示的声明异常
     * @param code Int
     * @param errorMsg String
     */
    protected fun handleResponseErrorCode(
        code: Int, errorMsg: String
    ) {
        Log.d("dede", "handleResponseErrorCode: $code")
        when (code) {
            //服务器定义异常
            401 -> throw AppExcpetion(
                ErrorType.NO_AUTH_ERROR,
                RuntimeException(errorMsg)
            )
            403 -> throw AppExcpetion(
                ErrorType.NO_ACCESS,
                RuntimeException(errorMsg)
            )
            404 -> throw AppExcpetion(
                ErrorType.SERVER_404_ERROR,
                RuntimeException(errorMsg)
            )
            500 -> throw AppExcpetion(
                ErrorType.SERVER_ERROR.code, errorMsg,
                RuntimeException(errorMsg)
            )
        }

    }
}
